package com.whut.service.impl;


import com.whut.mapper.ProjectBuildCheckMapper;
import com.whut.mapper.ProjectBuildMapper;
import com.whut.mapper.ProjectCheckMapper;
import com.whut.mapper.ProjectMapper;
import com.whut.model.Project;
import com.whut.model.ProjectBuild;
import com.whut.model.ProjectBuildCheck;
import com.whut.model.ProjectCheck;
import com.whut.service.ProjectService;
import com.whut.v_vo.ProjectBuildVO;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;


@Service("/projectService")
public class ProjectServiceImpl implements ProjectService {
    @Resource
    private ProjectMapper projectMapper;

    @Resource
    private ProjectBuildMapper projectBuildMapper;

    @Resource
    private ProjectBuildCheckMapper projectBuildCheckMapper;

    @Resource
    private ProjectCheckMapper projectCheckMapper;

    @Override
    public List<Project> all() {
        return projectMapper.findAll();
    }

    @Override
    public Project findProjectById(Integer projectId) {
        return Optional.ofNullable(projectMapper.findById(projectId))
                .orElseThrow(() -> new RuntimeException("未知异常"));
    }

    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public Project saveProject(Project project) {
        return Optional.ofNullable(project)
                .filter(t -> t.getName() != null)
                .map(t -> {
                    if (!projectMapper.findByName(t.getName()).isEmpty()) {
                        throw new RuntimeException("项目名称重复");
                    }
                    return t;
                })
                .map(t -> projectMapper.save(t))
                .filter(t -> t > 0)
                .map(t -> projectMapper.findById(project.getId()))
                .orElseThrow(() -> new RuntimeException("未知异常"));
    }

    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public Project modifyProject(Project project) {
        return Optional.ofNullable(project)
                .filter(t -> t.getId() != null)
                .map(t -> projectMapper.modifyById(t))
                .filter(t -> t > 0)
                .map(t -> project)
                .orElseThrow(() -> new RuntimeException("未知异常"));
    }

    @Override
    public List<ProjectBuildVO> projectBuilds(Integer projectId) {
        List<ProjectBuild> builds = projectBuildMapper.findByProjectId(projectId);
        List<ProjectCheck> checks = projectCheckMapper.findAll();
        List<ProjectBuildCheck> buildChecks = projectBuildCheckMapper.listByProjectId(projectId);


        return builds.stream()
                .sorted(Comparator.comparing(ProjectBuild::getBuild))
                .map(t -> convertProjectBuild(t, checks, buildChecks.stream().filter(x -> x.getProjectBuildId().equals(t.getId())).collect(Collectors.toList())))
                .collect(Collectors.toList());
    }

    @Override
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public ProjectBuildVO findProjectBuildById(Integer buildId) {
        ProjectBuild build = Optional.ofNullable(projectBuildMapper.findById(buildId))
                .orElseThrow(() -> new RuntimeException("BuildId不存在"));
        List<ProjectBuildCheck> buildChecks = projectBuildCheckMapper.listByBuildId(buildId);
        List<ProjectCheck> checks = projectCheckMapper.findAll();
        return convertProjectBuild(build, checks, buildChecks);
    }

    /**
     * 录入项目进度信息
     *
     * @param request
     * @return
     */
    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public ProjectBuildVO saveProjectBuild(ProjectBuildVO request) {
        boolean exists = projectBuildMapper.findByProjectAndBuild(request.getProjectId(), request.getName()) != null;
        if (exists) {
            throw new ArithmeticException("楼栋已存在");
        }
        ProjectBuild build = new ProjectBuild();
        build.setProjectId(request.getProjectId());
        build.setBuild(request.getName());
        build.setFloorNum(request.getFloorNum());
        build.setFamilyNum(request.getFamilyNum());
        build.setStandardFloorNum(request.getStandardFloorNum());
        build.setPileNum(request.getPileNum());
        build.setBetonConstructionFloorNum(request.getBetonConstructionFloorNum());

        List<ProjectBuildCheck> checks = request.getChecks().stream()
                .distinct()
                .flatMap(t ->
                        Optional.ofNullable(t.getFloors())
                                .filter(floors -> !floors.isEmpty())
                                .map(floors ->
                                        floors.stream()
                                                .map(floor -> {
                                                    ProjectBuildCheck check = new ProjectBuildCheck();
                                                    check.setProjectCheckId(t.getId());
                                                    check.setFloor(floor);
                                                    return check;
                                                })
                                )
                                .orElse(Stream.empty())
                )
                .collect(Collectors.toList());
        projectBuildMapper.save(build);
        checks.forEach(t -> t.setProjectBuildId(build.getId()));

        if (!checks.isEmpty()) {
            projectBuildCheckMapper.saveBatch(checks);
        }
        return findProjectBuildById(build.getId());
    }

    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public ProjectBuildVO modifyProjectBuild(ProjectBuildVO request) {
        ProjectBuild exists = projectBuildMapper.findByProjectAndBuild(request.getProjectId(), request.getName());
        if (!exists.getId().equals(request.getId())) {
            throw new ArithmeticException("楼栋已存在");
        }
        ProjectBuild build = new ProjectBuild();
        build.setId(request.getId());
        build.setProjectId(request.getProjectId());
        build.setBuild(request.getName());
        build.setFloorNum(request.getFloorNum());
        build.setFamilyNum(request.getFamilyNum());
        build.setStandardFloorNum(request.getStandardFloorNum());
        build.setPileNum(request.getPileNum());
        build.setBetonConstructionFloorNum(request.getBetonConstructionFloorNum());

        List<ProjectBuildCheck> checks = request.getChecks().stream()
                .flatMap(t ->
                        Optional.ofNullable(t.getFloors())
                                .filter(floors -> !floors.isEmpty())
                                .map(floors -> floors.stream()
                                        .map(floor -> {
                                            ProjectBuildCheck check = new ProjectBuildCheck();
                                            check.setProjectCheckId(t.getId());
                                            check.setFloor(floor);
                                            return check;
                                        })
                                )
                                .orElse(Stream.empty())
                )
                .collect(Collectors.toList());
        projectBuildMapper.modifyById(build);
        checks.forEach(t -> t.setProjectBuildId(build.getId()));
        if (!checks.isEmpty()) {
            projectBuildCheckMapper.deleteByBuildId(build.getId());
            projectBuildCheckMapper.saveBatch(checks);
        }
        return findProjectBuildById(build.getId());
    }

    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public ProjectBuildVO deleteByProjectBuildId(Integer buildId) {
        ProjectBuildVO build = findProjectBuildById(buildId);
        projectBuildMapper.deleteById(buildId);
        projectBuildCheckMapper.deleteByBuildId(buildId);
        return build;
    }

    private ProjectBuildVO convertProjectBuild(ProjectBuild build, List<ProjectCheck> checks, List<ProjectBuildCheck> buildChecks) {
        ProjectBuildVO vo = new ProjectBuildVO();
        vo.setId(build.getId());
        vo.setProjectId(build.getProjectId());
        vo.setName(build.getBuild());
        vo.setFloorNum(build.getFloorNum());
        vo.setFamilyNum(build.getFamilyNum());
        vo.setStandardFloorNum(build.getStandardFloorNum());
        vo.setPileNum(build.getPileNum());
        vo.setBetonConstructionFloorNum(build.getBetonConstructionFloorNum());
        vo.setChecks(
                checks.stream()
                        .map(c -> {
                            ProjectBuildVO.Check check = new ProjectBuildVO.Check();
                            check.setId(c.getId());
                            check.setName(c.getName());
                            check.setFloors(
                                    buildChecks.stream()
                                            .filter(bc -> bc.getProjectCheckId().equals(c.getId()))
                                            .map(ProjectBuildCheck::getFloor)
                                            .sorted()
                                            .collect(Collectors.toList())
                            );
                            return check;
                        })
                        .collect(Collectors.toList())
        );
        return vo;
    }

}
